//
//  ACCache.m
//  ACCache_Example
//
//  Created by autohome on 2021/8/7.
//  Copyright © 2021 CaiXiang. All rights reserved.
//

#import "ACCache.h"

@interface ACCache()

@property (nonatomic, strong, nullable) ACCacheConfiguration *config;

@end

@implementation ACCache

+ (instancetype)cacheWithConfiguration:(ACCacheConfiguration *)config {
    return [[self alloc] initWithCacheConfiguration:config];
}

- (instancetype)initWithCacheConfiguration:(ACCacheConfiguration *)config {
    if (!config) return nil;
    if (config.name.length == 0) return nil;
    _config = config;
    return [self initWithName:config.name];
}

- (instancetype)initWithName:(NSString *)name {
    if (name.length == 0) return nil;
    NSString *cacheFolder = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) firstObject];
    NSString *path = [cacheFolder stringByAppendingPathComponent:name];
    return [self initWithPath:path];
}

- (instancetype)initWithPath:(NSString *)path {
    if (path.length == 0) return nil;
    ACDiskCache *diskCache = [[ACDiskCache alloc] initWithPath:path];
    if (!diskCache) return nil;
    NSString *name = [path lastPathComponent];
    ACMemoryCache *memoryCache = [[ACMemoryCache alloc] initWithName:name];
    memoryCache.didEnterBackgroundBlock = ^(ACMemoryCache * _Nonnull mc) {
        
    };
    
    memoryCache.didReceiveMemoryWarningBlock = ^(ACMemoryCache * _Nonnull mc) {
        
    };
    self = [super init];
    if (self) {
        _diskCache = diskCache;
        _memoryCache = memoryCache;
    }
    return self;
}

@end

@implementation ACCache (ACExtension)

- (void)setObject:(nullable id<NSCoding>)object forKey:(NSString *)key {
    [self setObject:object forKey:key toDisk:NO];
}

- (void)setObject:(nullable id<NSCoding>)object forKey:(NSString *)key toDisk:(BOOL)yesOrNo {
    if (!key) return;
    if (_config.cacheType == ACCachePolicyDisk) {
        [_diskCache setObject:object forKey:key];
    } else {
        [_memoryCache setObject:object forKey:key];
        if (yesOrNo) {
            [_diskCache setObject:object forKey:key];
        }
    }
}

- (void)setObject:(nullable id)object vaule:(nullable id)vaule forKey:(NSString *)key {
    [self setObject:object vaule:vaule forKey:key toDisk:NO];
}

- (void)setObject:(nullable id)object vaule:(nullable id)vaule forKey:(NSString *)key toDisk:(BOOL)yesOrNo {
    if (!key) return;
    NSDictionary *parm = @{@"object":object,@"vaule":vaule};
    if (_config.cacheType == ACCachePolicyDisk) {
        [_diskCache setObject:parm forKey:key];
    } else {
        [_memoryCache setObject:parm forKey:key];
        if (yesOrNo) {
            [_diskCache setObject:parm forKey:key];
        }
    }
}

@end

@implementation ACCache (Extension)

- (BOOL)containsObjectForKey:(NSString *)key {
    BOOL conteains = NO;
    switch (_config.cacheType) {
        case ACCachePolicyMemory:
            conteains = [_memoryCache containsObjectForKey:key];
            break;
        case ACCachePolicyDisk:
            conteains = [_diskCache containsObjectForKey:key];
            break;
        case ACCachePolicyAll:
            conteains = [_memoryCache containsObjectForKey:key] || [_diskCache containsObjectForKey:key];
            break;
    }
    return conteains;
}

- (nullable id<NSCoding>)objectForKey:(NSString *)key {
    id<NSCoding> object = [_memoryCache objectForKey:key];
    if (!object) {
        object = [_diskCache objectForKey:key];
        if (object && (_config.cacheType == (ACCachePolicyMemory | ACCachePolicyAll))) {
            [_memoryCache setObject:object forKey:key];
        }
    }
    return object;
}

- (void)removeObjectForKey:(NSString *)key {
    [_memoryCache removeObjectForKey:key];
    [_diskCache removeObjectForKey:key];
}

- (void)removeAllObjects {
    [_memoryCache removeAllObjects];
    [_diskCache removeAllObjects];
}

- (NSString *)description {
    if (_config.name) return [NSString stringWithFormat:@"<%@: %p> (%@)", self.class, self, _config.name];
    else return [NSString stringWithFormat:@"<%@: %p>", self.class, self];
}

@end

@implementation ACCache (DBExtension)

@end
